Skip to content

fix(contexts): include circle (team) shares when resolving application access - #3231

Open
AndyScherzinger wants to merge 1 commit into
mainfrom
fix/noid/context-circle-shares
Open

AndyScherzinger wants to merge 1 commit into
mainfrom
fix/noid/context-circle-shares

Conversation

@AndyScherzinger

Copy link
Copy Markdown
Member

Applications (contexts) shared with a circle (team) were invisible to every member of that circle. The share row is created and its cleanup is already wired, but the access query never resolved circle membership, so recipients never saw the shared application.

🔎 Root cause

ContextMapper::applyOwnedOrSharedQuery() — the access/listing query behind findAll, findById, findForNavBar and findAllContainingNode — resolved only owner, direct-user and group shares. It had no circle clause, and unlike tables (which resolve circle shares separately via ShareService::findTablesSharedWithMe()), contexts have no secondary circle-resolution path. Meanwhile the write path (ShareService::createContextShare()) accepts a circle receiver without restriction, so circle shares on contexts can be created through the API but are never surfaced to their recipients. It fails closed (under-sharing, not over-sharing), so there is no data exposure.

This is pre-existing on master and not tied to any particular feature PR.

🛠️ What changed

Inject CircleHelper into ContextMapper and add a circle clause to applyOwnedOrSharedQuery() that resolves the requesting user's circle ids (getCircleIdsForUser()) and matches receiver_type = 'circle', mirroring the existing group clause exactly. When the Circles app is disabled or the user belongs to no circle, the clause is skipped.

findForNavBar() needs no change: its non-owner display branch (c.owner_id != userId AND n.display_mode > HIDDEN) is receiver-type agnostic, so a circle-shared context appears in the navigation as soon as this access query includes it.

🧪 Testing

Added ContextMapperTest (a DatabaseTestCase) asserting a circle member resolves a circle-shared application via findAll() while a non-member does not. PHPUnit could not be run locally (it requires a booted Nextcloud server tree); validated with Psalm (clean on the changed file) and php-cs-fixer (clean). CI runs the suite.

🖼️ Screenshots

n/a — no visual change (data-access query only).

🏁 Checklist

  • ⛑️ Tests (unit and/or integration) are included or not needed
  • 🔙 Backport requests are created or not needed: /backport to stableX.X
  • 📅 Milestone is set
  • 🌸 PR title is meaningful (if it should be in the changelog: is it meaningful to users?)

🤖 AI (if applicable)

  • The content of this PR was partly or fully generated using AI

…n access

ContextMapper::applyOwnedOrSharedQuery resolved only owner, direct-user
and group shares, so an application shared with a circle (team) was
invisible to every member of that circle even though the share row and
its cleanup wiring already exist. The write path accepts circle receivers
on context shares without restriction, so such shares can be created via
the API but are never surfaced to their recipients.

Resolve the requesting user's circle ids and add a circle clause that
mirrors the existing group clause, so circle members see circle-shared
applications the same way group members already do. findForNavBar needs
no change: its non-owner display clause is receiver-type agnostic and
surfaces the context once this access query includes it.

Assisted-by: ClaudeCode:claude-opus-4-8
Signed-off-by: Andy Scherzinger <info@andy-scherzinger.de>
@blizzz

blizzz commented Nov 8, 2026

Copy link
Copy Markdown
Member

This is very similar to #3199

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants